#include <QtGui>
#include "scene.h"
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
 #include "edge.h"
#include "sbml/SBMLTypes.h"
#include <QGraphicsItem>

SBMLDocument* createExampleEnzymaticReaction();
bool validateSBML(SBMLDocument *sbmlDoc);
bool writeExampleSBML(const SBMLDocument *sbmlDoc, const string& filename);

 Scene::Scene(QObject *parent)
     : QGraphicsScene(parent)
 {

     myItemColor = Qt::white;
     myTextColor = Qt::black;
     myLineColor = Qt::black;

	 line = 0;

	Letter.insert("A", 1);Letter.insert("B", 2);Letter.insert("C", 3);Letter.insert("D", 4);Letter.insert("E", 5);
	Letter.insert("F", 6);Letter.insert("G", 7);Letter.insert("H", 8);Letter.insert("I", 9);Letter.insert("J", 10);
	Letter.insert("K", 11);Letter.insert("L", 12);Letter.insert("M", 13);Letter.insert("N", 14);Letter.insert("O", 15);
	Letter.insert("P", 16);Letter.insert("Q", 17);Letter.insert("R", 18);Letter.insert("S", 19);Letter.insert("T", 20);
	//id = 0;

		/*for(int i = 0 ; i < 2000 ; i++ )
		{
			for ( int j = 0; j< 2000; j++ )
			{
				prevArray[i][j] = QPointF(-1,-1);
				costArray[i][j] = 50000;	
			}	
		}*/
		
		
 }
 void Scene::setMode(Mode mode)
 {
     myMode = mode;
 }
 void Scene::setItemType(DiagramItem::DiagramType type)
 {
     myItemType = type;
 }
 void Scene::setArrowType(Edge::EdgeType type)
 {
     myArrowType = type;
 }
  void Scene::diagramItemChange(DiagramItem *item)
 {
	 QGraphicsSceneMouseEvent mouse;
	for ( int i = 0 ; i < points.size()-1 ; i ++)
	{
		QLineF line = QLineF(item->pos(), item->pos() );
		QLineF itemLine = QLineF(points.at(i), points.at(i+1));
		QPointF intersectionPoint;
		itemLine.intersect(line, &intersectionPoint);
		if ( intersectionPoint == item->pos() )
		{
			item->setPos(item->x(), mouse.pos().y());
		}
	}
 }
 void Scene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
 {
	QGraphicsScene::mouseDoubleClickEvent(mouseEvent);		
 }

 void Scene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
 {
        DiagramItem *item;
     if (mouseEvent->button() != Qt::LeftButton)
         return;

	if( myMode == Insert )
	{
		item = new DiagramItem(myItemType);
		while ( ids.contains(item->myId) )
			item->myId = "di" + QString::number(rand());
		item->setBrush(myItemColor);
		item->setPen(QPen(Qt::black, 6));
		addItem(item);
		ids.append(item->myId);
		item->setPos(mouseEvent->scenePos());
        diagramItems.append(item);
		emit itemInserted(item);

	} 
	else if ((myMode == InsertEdge || myMode == InsertConEdge) )
	{
		QList<QGraphicsItem *> startItems = items(mouseEvent->scenePos());
		//while (startItems.count() && startItems.first()->type() != DiagramItem::Type )
		//	startItems.removeFirst();
		if ( myMode == InsertEdge )
		{
			while (startItems.count() && startItems.first()->type() != DiagramItem::Type )
				startItems.removeFirst();
		}

		if (startItems.count() == 0  && line == 0) {}
		else
		{	
			if ( startItems.count() > 0 && line == 0)
			{
				points.append(mouseEvent->scenePos());
			}
			if ( line != 0)
			{
				points.append(line->line().p2());

				line = 0;
			}
			line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(), mouseEvent->scenePos()));
			
			addItem(line);
		}
	}
	else if ( myMode == Text )
	{
		addNumber = new QGraphicsTextItem("Enter text");
		addNumber->setTextInteractionFlags(Qt::TextEditable | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
		addNumber->setFlag(QGraphicsItem::ItemIsMovable, true);
		addNumber->setFlag(QGraphicsItem::ItemIsSelectable, true);
		addItem(addNumber);
		addNumber->setPos(mouseEvent->scenePos());
		setMode(Scene::Mode(1));
	}
	else
		QGraphicsScene::mousePressEvent(mouseEvent);

 }
 void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
 {
     if ((myMode == InsertEdge || myMode == InsertConEdge)   && line != 0 ) 
	 {
		 line->setPen(QPen(myLineColor, 2));
		 if ( (line->line().p1().y() - 20) < mouseEvent->scenePos().y() && mouseEvent->scenePos().y() < (line->line().p1().y() + 20)) 
		 {
			QLineF newLine(QPointF(points.at(points.size()-1)), QPointF( mouseEvent->scenePos().x(), line->line().p1().y()));
			line->setLine(newLine);
		 }
		  else // ( ((line->line().p1().x() - 20) < mouseEvent->scenePos().x())  &&  (mouseEvent->scenePos().x() < (line->line().p1().x() + 20)))
		 {
			QLineF newLine(QPointF(points.at(points.size()-1)), QPointF(line->line().p1().x(), mouseEvent->scenePos().y()));
			line->setLine(newLine);
		 } 
     } else if (myMode == Move) {
         QGraphicsScene::mouseMoveEvent(mouseEvent);
     }
 }
 void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
 {
	if (myMode == InsertEdge  ) 
	{
            if ( !points.isEmpty())
           {

                QList<QGraphicsItem *> startItems = items(points.first());
                while (startItems.count() && startItems.first()->type() != DiagramItem::Type)
                    startItems.removeFirst();

                QList<QGraphicsItem *> endItems = items(points.last());
                while (endItems.count() && endItems.first()->type() != DiagramItem::Type)
                        endItems.removeFirst();

                if (endItems.count() > 0 && startItems.count() > 0
                && endItems.first()->type() == DiagramItem::Type && startItems.first()->type() == DiagramItem::Type
                && startItems.first() != endItems.first() )
                {
                        DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(endItems.first());
                        Edge *arrow;
                        DiagramItem *startItem = qgraphicsitem_cast<DiagramItem *>(startItems.first());
                        updatePoints(false);
                        arrow = new Edge(startItem, endItem, myArrowType);
						while ( ids.contains(arrow->myId) )
							arrow->myId = "e" + QString::number(rand());
                        arrow->points = points;
                        arrow->setColor(Qt::black);
                        arrow->setZValue(-1000.0);
                        addItem(arrow);
						ids.append(arrow->myId);
                        update();
                        QVector<QPointF> po = arrow->trackDiagramItem();

                        if ( (myArrowType < 3 || myArrowType == 6) && points.count() > 1)
                        {
                                DiagramItem *complexItem = new DiagramItem(DiagramItem::DiagramType(6));
								while ( ids.contains(complexItem->myId) )
									complexItem->myId = "di" + QString::number(rand());
                                complexItem->host = arrow;
                                arrow->isComplex = true;
                                arrow->complex = complexItem;
                                complexItem->setBrush(myItemColor);
                                complexItem->setPen(QPen(Qt::black, 6));
                                complexItem->setPos(QPointF(arrow->path().pointAtPercent(0.5)));
                                complexItem->setZValue(100.0);
                                addItem(complexItem);
								ids.append(complexItem->myId);
								diagramItems.append(complexItem);
                        }

                        update();
                        edges.append(arrow);
                        emit EdgeInserted(arrow);
                        points.clear();
                }
		}
		
	} else if ( myMode == InsertConEdge && points.size() != 1 )
	{
            if (!points.isEmpty())
            {
                QList<QGraphicsItem *> startItems = items(QRectF(QPointF(points.first().x()-2,points.first().y()-2),
							QPointF(points.first().x()+2,points.first().y()+2)));;

                //while (startItems.count() != 0  && startItems.first()->type() != DiagramItem::Type)
                //startItems.removeFirst();

                QList<QGraphicsItem *> endItems = items(QRectF(QPointF(mouseEvent->scenePos().x()-2,mouseEvent->scenePos().y()-2),
							QPointF(mouseEvent->scenePos().x()+2,mouseEvent->scenePos().y()+2)));
                while ( endItems.size() != 0 && endItems.first()->type() != Edge::Type)
                    endItems.removeFirst();
				while ( startItems.size() != 0 && (startItems.first()->type() != Edge::Type && startItems.first()->type() != DiagramItem::Type))
                    startItems.removeFirst();

                if (endItems.count() > 0 && startItems.count() > 0
                && endItems.first()->type() == Edge::Type)
                //&& startItems.first()->type() == DiagramItem::Type)
                {
					DiagramItem *startItem;

					if ( startItems.first()->type() == DiagramItem::Type )
					{
						startItem = qgraphicsitem_cast<DiagramItem *>(startItems.first());
					} else if ( startItems.first()->type() == Edge::Type )
					{
						Edge *endLine2 = qgraphicsitem_cast<Edge *>(startItems.first());

						startItem = new DiagramItem(DiagramItem::DiagramType(8));
						while ( ids.contains(startItem->myId) )
							startItem->myId = "di" + QString::number(rand());
						startItem->host = endLine2;
						startItem->setBrush(Qt::transparent);
						startItem->setPen(QPen(Qt::transparent, 6));
						//invisibleItem->setPos(QPointF(arrow->path().pointAtPercent(0.5)));
						startItem->setZValue(100.0);
						diagramItems.append(startItem);
						endLine2->invisibleItems.append(startItem);
						addItem(startItem);
						ids.append(startItem->myId);

						QPainterPath path(endLine2->path().elementAt(0));
						for ( int i = 1 ; i < endLine2->path().elementCount(); i++)
						{
							if ( endLine2->containPoint(QLineF(endLine2->path().elementAt(i-1),endLine2->path().elementAt(i)), points.first() ) ) 			
								break;	
							path.lineTo(endLine2->path().elementAt(i));
						}
						path.lineTo(points.first());
						startItem->per = endLine2->path().percentAtLength(path.length());
						QPointF ps = QPointF(startItem->host->path().pointAtPercent(startItem->per));
						startItem->setPos(ps);
					}


					Edge *endLine = qgraphicsitem_cast<Edge *>(endItems.first());

					DiagramItem *invisibleItem = new DiagramItem(DiagramItem::DiagramType(8));
					while ( ids.contains(invisibleItem->myId) )
						invisibleItem->myId = "di" + QString::number(rand());
                    invisibleItem->host = endLine;
                    invisibleItem->setBrush(Qt::transparent);
                    invisibleItem->setPen(QPen(Qt::transparent, 6));
                    //invisibleItem->setPos(QPointF(arrow->path().pointAtPercent(0.5)));
                    invisibleItem->setZValue(100.0);
					diagramItems.append(invisibleItem);
					endLine->invisibleItems.append(invisibleItem);
					
                    addItem(invisibleItem);
					ids.append(invisibleItem->myId);

					QPainterPath path(endLine->path().elementAt(0));
					for ( int i = 1 ; i < endLine->path().elementCount(); i++)
					{
						if ( endLine->containPoint(QLineF(endLine->path().elementAt(i-1),endLine->path().elementAt(i)), points.last() ) ) 			
							break;	
						path.lineTo(endLine->path().elementAt(i));
					}
					path.lineTo(points.last());
					invisibleItem->per = endLine->path().percentAtLength(path.length());
					invisibleItem->setPos(QPointF(endLine->path().pointAtPercent(invisibleItem->per)));
					

                    Edge *arrow; 
                    updatePoints(false);
                    arrow = new Edge(startItem, invisibleItem, myArrowType);
					while ( ids.contains(arrow->myId) )
						arrow->myId = "e" + QString::number(rand());
                    arrow->points = points;
                    arrow->setZValue(-1000.0);
                    addItem(arrow);
					ids.append(arrow->myId);
                    update();
                    arrow->trackDiagramItem( );
                    edges.append(arrow);
					endLine->conEdges.append(arrow);
                    emit EdgeInserted(arrow);
                    points.clear();
                }
            }
	} else 
		QGraphicsScene::mouseReleaseEvent(mouseEvent);
	
 }

 void Scene::drawBackground ( QPainter *painter, const QRectF &rect ) 
 {
	 if ( grid)
	 {	
		 painter->setPen(Qt::lightGray);
		 for( int i = 100; i < width(); i= i+100)
		 {
			painter->drawLine(QPointF(i,0),QPointF(i,2000));
			painter->drawText(QPointF(i-50,10), QString::number(Letter.value("A")+(i/100)-1));
		 }
		 for( int i = 100; i < height(); i= i+100)
		 {
			painter->drawLine(QPointF(0,i),QPointF(2000,i));
			painter->drawText(QPointF(10,i-50), Letter.key(i/100));
		 }
	 }
	 update();

 }
void Scene::updatePoints(bool t) // updates points so that there are no 3 consecutive points in the points vector
 {

 	line = 0;
	for (int j = 0 ; j < points.size() ; j++)
	{
		QList<QGraphicsItem *> lineItems = items(points.at(j));
		for (int i = 0; i < lineItems.size() ; i++)
		{
			if ( lineItems.at(i)->type() == QGraphicsLineItem::Type )
			{	
				removeItem(lineItems.at(i));
				lineItems.removeAt(i);
				i--;
			}
		}
	}
	if ( t ) //check is made to see if the line has been cancelled without completely drawn.
		points.clear();

	int i = 0;
	while ( i+2 < points.size())
	{
		if ( (points.at(i).x() <= points.at(i+1).x()+0.005 && points.at(i).x() > points.at(i+1).x()- 0.005
				&& points.at(i+1).x() <= points.at(i+2).x()+ 0.005 && points.at(i+1).x() > points.at(i+2).x() - 0.005)
			 || (points.at(i).y() <= points.at(i+1).y()+0.005 && points.at(i).y() > points.at(i+1).y()- 0.005
				&& points.at(i+1).y() <= points.at(i+2).y()+ 0.005 && points.at(i+1).y() > points.at(i+2).y()- 0.005) )
		{
			 points.erase(points.begin()+ i+1);
			 i--;
		} 
		i++;
	}
 }
DiagramItem* Scene::returnItem(QString id) // returns the diagram item with the given id; used in xml
{
	QList<QGraphicsItem *> itemList = items();
	for (int i = 0; i < itemList.size() ; i++)
	{

		if ( itemList.at(i)->type() == DiagramItem::Type )
		{
			DiagramItem *item = qgraphicsitem_cast<DiagramItem *>(itemList.at(i));
			if ( id == item->myId )
				return item;
		}
	}
        return 0;

}

Edge* Scene::returnPath(QString id) // returns the edge with the given id; used in xml
{
	QList<QGraphicsItem *> itemList = items();
	for (int i = 0; i < itemList.size() ; i++)
	{

		if ( itemList.at(i)->type() == Edge::Type )
		{
			Edge *item = qgraphicsitem_cast<Edge *>(itemList.at(i));
			if ( id == item->myId )
				return item;
		}
	}
        return 0;

}
void Scene::filtering()
{
	QList<QGraphicsItem *> Item = selectedItems();
	QList<QGraphicsItem *> Items = items();
	DiagramItem *item = qgraphicsitem_cast<DiagramItem *>(Item.first());
	item->filtered = true;

	foreach ( QGraphicsItem* item2, Items)
	{
		if (item2->type() == QGraphicsPathItem::Type)
		{
			Edge *edge = qgraphicsitem_cast<Edge *>(item2);
			if ( edge->startItem() != item && edge->endItem() != item )
				edge->setColor(Qt::lightGray);
		}
	}
	clearSelection();
}
void Scene::unfiltering()
{
	QList<QGraphicsItem *> Item = selectedItems();
	QList<QGraphicsItem *> Items = items();
	DiagramItem *item = qgraphicsitem_cast<DiagramItem *>(Item.first());
	item->filtered = false;

	foreach ( QGraphicsItem* item2, Items)
	{
		if (item2->type() == QGraphicsPathItem::Type)
		{
			Edge *edge = qgraphicsitem_cast<Edge *>(item2);
			if ( edge->startItem() != item && edge->endItem() != item )
				edge->setOldColor();
		}
	}
	clearSelection();
}

QString Scene::saveToXML()
{
	/*auto_ptr<DiagramType> typ ( 50 , 50 ),
	auto_ptr<Diagram> d (typ) ;
	d->*/

	QString *outputString = new QString();
	QXmlStreamWriter xmlFile(outputString);
	xmlFile.setAutoFormatting(true);
	xmlFile.writeStartDocument("1.0");
	xmlFile.writeStartElement("mimVis:Diagram");
	xmlFile.writeAttribute( "width", QString::number(itemsBoundingRect().width())  );
	xmlFile.writeAttribute( "height", QString::number(itemsBoundingRect().height())   );
	xmlFile.writeNamespace( "http://lmp.nci.nih.gov/mim/mimVisLevel1", "mimVis");

	for( int i = 0; i< diagramItems.size(); i++ )
	{
		DiagramItem *item = diagramItems.at(i);
		if ( item->diagramType() < 7)
		{
			xmlFile.writeStartElement("mimVis:EntityGlyph");
			xmlFile.writeAttribute("type", item->returnEnum(item->diagramType()));
			xmlFile.writeAttribute("visId", item->myId );
			xmlFile.writeAttribute("color", "000000" );
			xmlFile.writeAttribute("width", QString::number(item->width)  );
			xmlFile.writeAttribute("height", QString::number(item->height)   );
			if ( item->diagramType() == 6 )
				xmlFile.writeAttribute("position", QString::number(item->per));
			if ( item->diagramType() < 7 && item->diagramType() != 4 ) // sourcesink does not have display name attribute
				xmlFile.writeAttribute("displayName", item->text() );
			xmlFile.writeAttribute("centerX", QString::number(item->pos().x())  );
			xmlFile.writeAttribute("centerY", QString::number(item->pos().y())  );
                        //xmlFile.writeAttribute("mimVis:groupRef", "" );

			xmlFile.writeEndElement();
		}

	}
	for ( int i = 0; i< edges.size(); i++ )
	{
		Edge *item = edges.at(i);
		xmlFile.writeStartElement("mimVis:InteractionGlyph"); 
		xmlFile.writeAttribute("visId", item->myId );

		xmlFile.writeAttribute("color", item->Color().name() );

		xmlFile.writeStartElement("mimVis:Point");

		xmlFile.writeAttribute("x", QString::number(item->points.first().x()) );
		xmlFile.writeAttribute("y", QString::number(item->points.first().y()) );
		if ( (item->points.at(1).x() - item->points.first().x()) > 2)
			xmlFile.writeAttribute("relX", QString::number(1.0));
		else if ( (item->points.first().x() - item->points.at(1).x() ) > 2 )
			xmlFile.writeAttribute("relX", QString::number(-1.0));
		else
			xmlFile.writeAttribute("relX", QString::number(0.0));
		if ((item->points.at(1).y() - item->points.first().y()) > 2)
			xmlFile.writeAttribute("relY", QString::number(1.0));
		else if ( (item->points.first().y() - item->points.at(1).y() ) > 2 )
			xmlFile.writeAttribute("relY", QString::number(-1.0));
		else
			xmlFile.writeAttribute("relY", QString::number(0.0));
		
		xmlFile.writeAttribute("arrowHead", item->returnEnumFirst(item->edgeType()) );
		xmlFile.writeAttribute("visRef", item->startItem()->myId );
		xmlFile.writeEndElement();
			
		for ( int i = 1; i < item->points.size()-2; i++)
		{
			xmlFile.writeStartElement("mimVis:Point");
			xmlFile.writeAttribute("x", QString::number((item->points.at(i).x()+item->points.at(i+1).x())/2 ) );
			xmlFile.writeAttribute("y", QString::number((item->points.at(i).y()+item->points.at(i+1).y())/2 ) );
			xmlFile.writeEndElement();
		}

		xmlFile.writeStartElement("mimVis:Point");
		xmlFile.writeAttribute("x", QString::number(item->points.last().x() ) );
		xmlFile.writeAttribute("y", QString::number(item->points.last().y() ) );

		if ( (item->points.at(item->points.size()-2).x() - item->points.last().x()) > 2)
			xmlFile.writeAttribute("relX", QString::number(1.0));
		else if ( (item->points.last().x() - item->points.at(item->points.size()-2).x() ) > 2 )
			xmlFile.writeAttribute("relX", QString::number(-1.0));
		else
			xmlFile.writeAttribute("relX", QString::number(0.0));
		if ((item->points.at(item->points.size()-2).y() - item->points.last().y()) > 2)
			xmlFile.writeAttribute("relY", QString::number(1.0));
		else if ( (item->points.last().y() - item->points.at(item->points.size()-2).y() ) > 2 )
			xmlFile.writeAttribute("relY", QString::number(-1.0));
		else
			xmlFile.writeAttribute("relY", QString::number(0.0));

			xmlFile.writeAttribute("arrowHead", item->returnEnumSecond(item->edgeType()) );
            xmlFile.writeAttribute("visRef", item->endItem()->myId );
			xmlFile.writeEndElement();

			if ( item->intrans )
				xmlFile.writeTextElement("mimVis:anchorRef", item->trans->myId);
			if ( item->isComplex )
				xmlFile.writeTextElement("mimVis:anchorRef", item->complex->myId);

			foreach ( DiagramItem* it, item->invisibleItems )
				xmlFile.writeTextElement("mimVis:anchorRef", it->myId);
		

			xmlFile.writeEndElement();
	}
	for( int i = 0; i< diagramItems.size(); i++ )
	{
		DiagramItem *item = diagramItems.at(i);
		if ( item->diagramType() > 6)
		{
			DiagramItem *item = diagramItems.at(i);
			xmlFile.writeStartElement("mimVis:Anchor");
			xmlFile.writeAttribute("visId", item->myId );
			xmlFile.writeAttribute("position", QString::number(item->per));
			xmlFile.writeAttribute("type", item->returnEnum(item->diagramType()));
			xmlFile.writeEndElement();
		}
	}
	xmlFile.writeEndDocument();

	return *outputString;

}
void Scene::loadFromXml(QIODevice *xmlData)
{
	QXmlStreamReader xmlReader(xmlData);

	while (!xmlReader.atEnd()) 
	{
		xmlReader.readNext();
		
 		if ( xmlReader.isStartElement() && xmlReader.name() == "Diagram" )
		{
			while(!(xmlReader.isEndElement() && xmlReader.name() == "Diagram") )
			{
			xmlReader.readNext();
            int id = 0;


			if ( xmlReader.isStartElement() && xmlReader.name() == "EntityGlyph" )
			{
				QString name = xmlReader.attributes().value("type").toString(); 
				if ( name == "SimplePhysicalEntity" )
					id = 0;
				else if ( name == "EntityFeature" )
					id = 1;
				else if ( name == "Modifier" )
					id = 2;
				else if ( name == "ConceptualEntity" )
					id = 3;
                else if ( name == "SourceSink" )
					id = 4;
				else if ( name == "RestrictedCopy" )
					id = 5;
				else if ( name == "ExplicitComplex" )
					id = 6;

				DiagramItem* item;
				item = new DiagramItem(DiagramItem::DiagramType(id));
				qreal posx , posy;
				int width;
				int height;
				QString id3;
				
				posx = xmlReader.attributes().value("centerX").toString().toFloat(); 
				posy = xmlReader.attributes().value("centerY").toString().toFloat(); 
				id3 = xmlReader.attributes().value("visId").toString();
				if ( id < 7 && id != 4 )
					item->setText(xmlReader.attributes().value("displayName").toString()); 
				if ( id == 6 )
					item->per = xmlReader.attributes().value("position").toString().toFloat();
				if ( id < 4 )
				{
					width = xmlReader.attributes().value("width").toString().toInt();
					height = xmlReader.attributes().value("height").toString().toInt();
				}

                if ( !posx || !posy || !width || !height || id3 == "")
				{
					xmlReader.raiseError(QObject::tr("Unknown  Entity attribute"));
					break;
				}
				item->myId = id3;
				if ( id < 4 )
					item->setWidthHeight(width, height);
				item->setPos(QPointF(posx, posy));
				item->setZValue(100);
				addItem(item);
				ids.append(item->myId);
				diagramItems.prepend(item);

			} else if ( xmlReader.isStartElement() && xmlReader.name() == "Anchor" )
			{
				QString name = xmlReader.attributes().value("type").toString(); 
				if ( name == "InTrans" )
					id = 7;
				else if ( name == "Invisible" )
					id = 8;

				DiagramItem* item;
				item = new DiagramItem(DiagramItem::DiagramType(id));
				item->myId = xmlReader.attributes().value("visId").toString();
				item->per = xmlReader.attributes().value("position").toString().toFloat();
				//
				item->setZValue(100);
				addItem(item);
				ids.append(item->myId);
				diagramItems.prepend(item);
			}
			}
		}
	}
	if ( xmlReader.hasError() )
	{
		QMessageBox msgBox;
		msgBox.setText(xmlReader.errorString());
		msgBox.exec();
	}

}
void Scene::loadFromXmlInteraction(QIODevice *xmlData)
{
	QXmlStreamReader xmlReader(xmlData);


	while (!xmlReader.atEnd()) 
	{
		xmlReader.readNext();

		if ( xmlReader.isStartElement() && xmlReader.name() == "Diagram" )
		{
			while(!(xmlReader.isEndElement() && xmlReader.name() == "Diagram") )
			{
			xmlReader.readNext();

				if ( xmlReader.isStartElement() && xmlReader.name().toString() == "InteractionGlyph" )
				{
				Edge* item;
                int  edgeT = -1;
				QString start,end, id, id2, type1, type2;
                float posx,posy,relx, rely;
				QColor col;
                QVector<QPointF> dummy;
				QList<DiagramItem*> anchors;
                bool h = false;
				bool h1 = false;

				id = xmlReader.attributes().value("visId").toString();
				col = QColor(xmlReader.attributes().value("color").toString());

				if ( id == "" || col == ""  )
				{
					xmlReader.raiseError(QObject::tr("Unknown  Interaction attribute"));
					break;
				}

				while(!(xmlReader.isEndElement() && xmlReader.name().toString() == "InteractionGlyph"))
				{
					xmlReader.readNext();

					if (xmlReader.isStartElement())
					{
						 if ( xmlReader.name() == "Point" ) 
						{
							if ( dummy.isEmpty())
							{
								start = xmlReader.attributes().value("visRef").toString();
								type1 = xmlReader.attributes().value("arrowHead").toString();
							}
							else
							{
								end = xmlReader.attributes().value("visRef").toString();
								type2 = xmlReader.attributes().value("arrowHead").toString();
							}

							posx = xmlReader.attributes().value("x").toString().toFloat();
							posy = xmlReader.attributes().value("y").toString().toFloat();
                            dummy.append(QPointF(posx,posy));

                            if ( h == false)
                            {
								relx = xmlReader.attributes().value("relX").toString().toFloat();
								rely = xmlReader.attributes().value("relY").toString().toFloat();
                                h = true;
							}
						} else if ( xmlReader.name() == "anchorRef" ) 
						{
							DiagramItem* item = returnItem(xmlReader.readElementText());
							anchors.prepend(item);
						}
					}
				}

				QVector<QPointF> points;
				points.append(dummy.first());
				if (rely == 1 || rely == -1)
				{
					h = false;
					h1 = false;
				}
				else
				{
					h = true;
					h1 = true;
				}

                for (int i = 0; i < dummy.size()-1 ; i++)
                {
                    if (h)
                    {
                        points.append(QPointF(dummy.at(i+1).x(),dummy.at(i).y()));
                        h = false;
                    } else {
                        points.append(QPointF(dummy.at(i).x(),dummy.at(i+1).y()));
                        h = true;
                    }
                }
                points.append(dummy.last());		

				if ( type2 != "")
				{
					if ( type2 == "NonCovalentReversibleBinding")
						edgeT = 0;
					else if ( type2 == "CovalentModification")
						edgeT = 1;
					else if ( type2 == "CovalentIrreversibleBinding" )
						edgeT = 2 ;
					else if ( type2 == "StochiometricConversion" )
						edgeT = 3;
					else if ( type2 == "ProductionWithoutLoss" )
						edgeT = 4;
					else if ( type2 == "TemplateReaction" )
						edgeT = 5;
					else if ( type2 == "StateCombination" )
						edgeT = 6;
					else if ( type2 == "Line" )
						edgeT = 7;
					else if ( type2 == "NextFeature" )
						edgeT = 8;
					else if ( type2 == "CovalentBondCleavage" )
						edgeT = 9;
					else if ( type2 == "Stimulation" )
						edgeT = 10;
					else if ( type2 == "NecessaryStimulation" )
						edgeT = 11;
					else if ( type2 == "Inhibition" )
						edgeT = 12;
					else
						edgeT = 13;
				}

                if ( points.size() < 2 || edgeT == -1)
				{
					xmlReader.raiseError(QObject::tr("Not enough points to create an interaction"));
					break;
				}

                if ( end == "" || start == "" || type1 == "" || type2 == "")
				{
					xmlReader.raiseError(QObject::tr("Not enough information to create an interaction"));
					break;
				}
				item = new Edge(returnItem(start), returnItem(end), Edge::EdgeType(edgeT));
				item->points = points;
				if ( h1 == false)
					item->startUp = 1;
				else 
					item->startUp = 2;
				if ( returnItem(start)->diagramType() == 8)
					returnItem(start)->setPos(points.first());
				if ( returnItem(end)->diagramType() == 8)
				{
					DiagramItem* dummy = returnItem(end);
					dummy->setPos(points.last());
				}


				if ( type1 == "BranchingLeft")
					item->branchLeft = true;
				else if ( type1 == "BranchingRight" )
					item->branchRight = true;
				
				item->setZValue(-1000.0);			
				item->myId = id;

				if ( !anchors.isEmpty() )
                {
					foreach( DiagramItem* item2, anchors )
					{
						item2->host = item;
						
						item2->setZValue(100.0);
						if ( item2->diagramType() == 6 )
						{
							item->isComplex = true;
							item->complex = item2;
						}
						else if ( item2->diagramType() == 7 )
						{
							item->intrans = true;
							item->trans = item2;
						}
                        else if ( item2->diagramType() == 8 )
							item->invisibleItems.prepend(item2);
					}
				}

				addItem(item);
				ids.append(item->myId);
				edges.prepend(item);
				item->change();
				item->setColor(col);
				points.clear();	
				}
			}
		}
	}
	if ( xmlReader.hasError() )
	{
		QMessageBox msgBox;
		msgBox.setText(xmlReader.errorString());
		msgBox.exec();
	}
	foreach ( Edge* edge, edges)
	{
		if (edge->endItem()->diagramType() == 8 )
			edge->endItem()->host->addEdge(edge);
	}
}
void Scene::drawSemiAuto(QList<QGraphicsItem *> items)
{
		QPointF startPoint = items.first()->pos();
		QPointF endPoint = items.at(1)->pos();

		int ex, ey;
		int sx = int(startPoint.x());
		int sy = int(startPoint.y());
		int wi =  int(abs(sx - endPoint.x())/ 5);
		int he =  int(abs(sy - endPoint.y())/ 5);
		if ( sx > endPoint.x())
			ex = sx - wi*5;
		else
			ex = sx + wi*5;
		if ( sy > endPoint.y())
			ey = sy - he*5;
		else
			ey = sy + he*5;

		costArray[QString::number(sx) + QString::number(sy)] = 0;
		prevArray[QString::number(sx) + QString::number(sy)] = QPointF(-1,-1);
		costArray2[QString::number(ex) + QString::number(ey)] = 0;
		prevArray2[QString::number(ex) + QString::number(ey)] = QPointF(-1,-1);

		QPointF minDist;
		bool test = true;

		heap.push_back(startPoint);
		heap2.push_back(QPointF(ex,ey));
		
		
		int cost;
		
		clock_t start,end;
		double dif;
		start = clock();
		while( test )
		{	
			int i,j, m,n;

			minDist = heap.first();
			deleteMinHeap();

			i = int(minDist.x());
			j = int(minDist.y());
			m = prevArray[QString::number(i) + QString::number(j)].x();
			n = prevArray[QString::number(i) + QString::number(j)].y();

			if ( j+he != n && j+he  <=  max(sy,ey) )
			{
				cost = costArray[QString::number(i) + QString::number(j)]+2;
				if ( m != i && n != j+he )
					cost+= 20;
				cost += cross(QPointF(i, j+he ), minDist);

				if ( !costArray.contains(QString::number(i) + QString::number(j+he)) || costArray[QString::number(i) + QString::number(j+he)] > cost )
				{
					if( !costArray.contains(QString::number(i) + QString::number(j+he)) )
					{
						costArray[QString::number(i) + QString::number(j+he)] = cost;
						insertHeap(QPointF(i,j+he));
					}
					else
					{
						costArray[QString::number(i) + QString::number(j+he)] = cost;
						decreaseKeyHeap(QPointF(i,j+he));
					}
					prevArray[QString::number(i) + QString::number(j+he)] = minDist;
				}

			}
			if ( j-he != n && j-he >= min(sy,ey) )
			{
				cost = 0;
				cost+= costArray[QString::number(i) + QString::number(j)]+2;
				if ( m != i  && n != j-he )
					cost+= 20;
				cost += cross(QPointF(i, j - he), minDist);

				if ( !costArray.contains(QString::number(i) + QString::number(j-he)) || costArray[QString::number(i) + QString::number(j-he)] > cost )
				{
					if(!costArray.contains(QString::number(i) + QString::number(j-he))  )
					{
						costArray[QString::number(i) + QString::number(j-he)] = cost;
						insertHeap(QPointF(i,j-he));
					}
					else
					{
						costArray[QString::number(i) + QString::number(j-he)] = cost;
						decreaseKeyHeap(QPointF(i,j-he));

					}
					prevArray[QString::number(i) + QString::number(j-he)] = minDist;
				}

			}
			if ( i+wi != m && i+wi <= max(sx,ex) )
			{
				cost = 0;
				cost+= costArray[QString::number(i) + QString::number(j)]+2;
				if ( m != i+wi  && n != j )
					cost+= 20;
				cost += cross(QPointF(i + wi,j), minDist);

				if ( !costArray.contains(QString::number(i+wi) + QString::number(j)) || costArray[QString::number(i+wi) + QString::number(j)] > cost )
				{
					if(!costArray.contains(QString::number(i+wi) + QString::number(j))  )
					{
						costArray[QString::number(i+wi) + QString::number(j)] = cost;
						insertHeap(QPointF(i+wi,j));
					}
					else
					{
						costArray[QString::number(i+wi) + QString::number(j)] = cost;
						decreaseKeyHeap(QPointF(i+wi,j));

					}
					prevArray[QString::number(i+wi) + QString::number(j)] = minDist;
				}

			}
			if ( i-wi != m && i-wi >= min(sx,ex)  )
			{
				cost = 0;
				cost+= costArray[QString::number(i) + QString::number(j)]+2;
				if ( m != i-wi  && n != j )
					cost+= 20;
				cost += cross(QPointF(i - wi, j), minDist);
				
				if ( !costArray.contains(QString::number(i-wi) + QString::number(j)) || costArray[QString::number(i-wi) + QString::number(j)] > cost )
				{
					if(!costArray.contains(QString::number(i-wi) + QString::number(j))  )
					{
						costArray[QString::number(i-wi) + QString::number(j)] = cost;
						insertHeap(QPointF(i-wi,j));
					}
					else
					{
						costArray[QString::number(i-wi) + QString::number(j)] = cost;
						decreaseKeyHeap(QPointF(i-wi,j));

					}
					prevArray[QString::number(i-wi) + QString::number(j)] = minDist;
				}

			}

			 minDist = heap2.first();
			deleteMinHeap2();

			i = int(minDist.x());
			j = int(minDist.y());
			m = prevArray2[QString::number(i) + QString::number(j)].x();
			n = prevArray2[QString::number(i) + QString::number(j)].y();

			if ( j+he != n && j+he  <=  max(sy,ey) )
			{
				cost = costArray2[QString::number(i) + QString::number(j)]+2;
				if ( m != i && n != j+he )
					cost+= 20;
				cost+= cross(QPointF(i, j+he ), minDist);

				if ( !costArray2.contains(QString::number(i) + QString::number(j+he)) || costArray2[QString::number(i) + QString::number(j+he)] > cost )
				{
					if( !costArray2.contains(QString::number(i) + QString::number(j+he)) )
					{
						costArray2[QString::number(i) + QString::number(j+he)] = cost;
						insertHeap2(QPointF(i,j+he));
					}
					else
					{
						costArray2[QString::number(i) + QString::number(j+he)] = cost;
						decreaseKeyHeap2(QPointF(i,j+he));
					}
					prevArray2[QString::number(i) + QString::number(j+he)] = minDist;
				}

			}
			if ( j-he != n && j-he >= min(sy,ey) )
			{
				cost = 0;
				cost+= costArray2[QString::number(i) + QString::number(j)]+2;
				if ( m != i  && n != j-he )
					cost+= 20;
				cost += cross(QPointF(i, j - he), minDist);
				
				if ( !costArray2.contains(QString::number(i) + QString::number(j-he)) || costArray2[QString::number(i) + QString::number(j-he)] > cost )
				{
					if(!costArray2.contains(QString::number(i) + QString::number(j-he))  )
					{
						costArray2[QString::number(i) + QString::number(j-he)] = cost;
						insertHeap2(QPointF(i,j-he));
					}
					else
					{
						costArray2[QString::number(i) + QString::number(j-he)] = cost;
						decreaseKeyHeap2(QPointF(i,j-he));

					}
					prevArray2[QString::number(i) + QString::number(j-he)] = minDist;
				}

			}
			if ( i+wi != m && i+wi <= max(sx,ex) )
			{
				cost = 0;
				cost+= costArray2[QString::number(i) + QString::number(j)]+2;
				if ( m != i+wi  && n != j )
					cost+= 20;
				cost += cross(QPointF(i + wi,j), minDist);
				
				if ( !costArray2.contains(QString::number(i+wi) + QString::number(j)) || costArray2[QString::number(i+wi) + QString::number(j)] > cost )
				{
					if(!costArray2.contains(QString::number(i+wi) + QString::number(j))  )
					{
						costArray2[QString::number(i+wi) + QString::number(j)] = cost;
						insertHeap2(QPointF(i+wi,j));
					}
					else
					{
						costArray2[QString::number(i+wi) + QString::number(j)] = cost;
						decreaseKeyHeap2(QPointF(i+wi,j));

					}
					prevArray2[QString::number(i+wi) + QString::number(j)] = minDist;
				}

			}
			if ( i-wi != m && i-wi >= min(sx,ex)  )
			{
				cost = 0;
				cost+= costArray2[QString::number(i) + QString::number(j)]+2;
				if ( m != i-wi  && n != j )
					cost+= 20;
				cost += cross(QPointF(i - wi, j), minDist);
				
				if ( !costArray2.contains(QString::number(i-wi) + QString::number(j)) || costArray2[QString::number(i-wi) + QString::number(j)] > cost )
				{
					if(!costArray2.contains(QString::number(i-wi) + QString::number(j))  )
					{
						costArray2[QString::number(i-wi) + QString::number(j)] = cost;
						insertHeap2(QPointF(i-wi,j));
					}
					else
					{
						costArray2[QString::number(i-wi) + QString::number(j)] = cost;
						decreaseKeyHeap2(QPointF(i-wi,j));

					}
					prevArray2[QString::number(i-wi) + QString::number(j)] = minDist;
				}

			}
			if ( costArray.contains(QString::number(heap2.first().x()) + QString::number(heap2.first().y())) || costArray2.contains(QString::number(heap.first().x()) + QString::number(heap.first().y())) )
				test = false;
		}

		int finalx, finaly;
		QPointF final;
		if ( heap.contains(heap2.first()) )
			final = heap2.first();
		else
			final = heap.first();

		QPointF p;
		int i = int(final.x());
		int j = int(final.y());
		QVector<QPointF> point;

		while ( i != -1 || j != -1 )
		{
			p  = prevArray[QString::number(i) + QString::number(j)];
			point.push_front(QPointF(i,j));
			i = int(p.x());
			j = int(p.y());

		}
		i = prevArray2[QString::number(final.x()) + QString::number(final.y())].x();
		j = prevArray2[QString::number(final.x()) + QString::number(final.y())].y();

		while ( i != -1 || j != -1 )
		{
			p  = prevArray2[QString::number(i) + QString::number(j)];
			point.push_back(QPointF(i,j));
			i = int(p.x());
			j = int(p.y());

		}
		points = point;
        updatePoints(false);
		DiagramItem *startItem = qgraphicsitem_cast<DiagramItem *>(items.first());
		DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(items.at(1));
		Edge *arrow = new Edge(startItem, endItem , myArrowType);
		while ( ids.contains(arrow->myId) )
			arrow->myId = "e" + QString::number(rand());
		
		arrow->points = points;
		arrow->setPen(QPen(Qt::black, 2));
		arrow->setZValue(-1000.0);
		addItem(arrow);
		ids.append(arrow->myId);
		QVector<QPointF> po = arrow->trackDiagramItem();

		if ( (myArrowType < 3 || myArrowType == 6) )
		{
			DiagramItem *complexItem = new DiagramItem(DiagramItem::DiagramType(6));
			while ( ids.contains(complexItem->myId) )
				complexItem->myId = "di" + QString::number(rand());
			complexItem->host = arrow;
			arrow->isComplex = true;
			arrow->complex = complexItem;
			QPointF p = QPointF((complexItem->host->points.first().x() + complexItem->host->points.at(1).x()) / 2, (complexItem->host->points.first().y() + complexItem->host->points.at(1).y()) / 2);
			complexItem->setBrush(myItemColor);
			complexItem->setPen(QPen(Qt::black, 6));
			complexItem->setPos(p);
			complexItem->setZValue(100.0);
			addItem(complexItem);
			diagramItems.append(complexItem);
			ids.append(complexItem->myId);
		}

		update();
        edges.append(arrow);
		emit EdgeInserted(arrow);

		costArray.clear();
		prevArray.clear();
		costArray2.clear();
		prevArray2.clear();
		heap.clear();
		heap2.clear();
			
}

SBMLDocument* Scene::createExampleEnzymaticReaction(const QString &modelName)
{

    sbmlDoc = new SBMLDocument();
	Model* model = sbmlDoc->createModel(modelName.toStdString());
	model->setId("Model");

    const string compName = "default";

    Compartment* comp = model->createCompartment();
    comp->setId(compName);
	comp->setSize(100.0);

    for ( int i = 0; i < diagramItems.size() ; i++)
    {
		if ( diagramItems.at(i)->diagramType() < 7 )
		{
			Species *sp;

			sp = model->createSpecies();
			sp->setCompartment(compName);
			sp->setName(diagramItems.at(i)->text().toStdString());
			sp->setId(diagramItems.at(i)->myId.toStdString());
			sp->setMetaId(diagramItems.at(i)->myId.toStdString());
			//int h = sp->setNotes(diagramItems.at(i)->notes.toStdString());
			/*string speciesType = diagramItems.at(i)->returnEnum(diagramItems.at(i)->diagramType()).toStdString(); // mim annotation
			//const string annotationStr = "<annotation> <mim:extention> Annotation deneme  </mim:extention>  </annotation> ";
			const string model_history_annotation = 
			"<annotation>\r\n"
			"  <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:vCard=\"http://www.w3.org/2001/vcard-rdf/3.0#\" xmlns:bqbiol=\"http://biomodels.net/biology-qualifiers/\" xmlns:bqmodel=\"http://biomodels.net/model-qualifiers/\">\r\n"
			"    <rdf:Description rdf:about=\"#\">\r\n"
			"      <bqbiol:isVersionOf>\r\n"
			"        <rdf:Bag>\r\n"
			"          <rdf:li rdf:resource=\"http://www.geneontology.org/#GO:0005892\"/>\r\n"
			"          <rdf:li rdf:resource=\"http://www.ebi.ac.uk/interpro/#IPR002394\"/>\r\n"
			"        </rdf:Bag>\r\n"
			"      </bqbiol:isVersionOf>\r\n"
			"      <bqbiol:is>\r\n"
			"        <rdf:Bag>\r\n"
			"          <rdf:li rdf:resource=\"http://www.geneontology.org/#GO:0005895\"/>\r\n"
			"        </rdf:Bag>\r\n"
			"      </bqbiol:is>\r\n"
			"    </rdf:Description>\r\n"
			"  </rdf:RDF>\r\n"
			" </annotation>\r\n" ;
			//"	<mim:extention>\r\n";

			//XMLNode *mimNode = XMLNode::convertStringToXMLNode();
			int k = sp->setAnnotation(model_history_annotation);
			//sp->appendAnnotation("</annotation>\r\n");
			//sp->appendAnnotation(model_history_annotation);*/
		}

    }
	for ( int i = 0; i < edges.size() ; i++)
    {
		if ( edges.at(i)->edgeType() < 7 ) //TO DO: cleavage eklenecek
		{
			Reaction *re;

			 re = model->createReaction();
//			 re->setName(edges.at(i)->name.toStdString());
			 re->setId(edges.at(i)->myId.toStdString());
			 re->setMetaId(edges.at(i)->myId.toStdString());
			 if ( edges.at(i)->edgeType() == 0 )
				re->setReversible(true);
			 else
				 re->setReversible(false);
			 string reactionType = edges.at(i)->returnEnumSecond(edges.at(i)->edgeType()).toStdString(); // mim annotation
			// string reactionAnnotation = edges.at(i)->annotation.toStdString(); // mim annotation
			SpeciesReference* ra = re->createReactant();
			ra->setSpecies(edges.at(i)->startItem()->myId.toStdString());

			 if ( edges.at(i)->edgeType() < 3 || edges.at(i)->edgeType() == 6)
			 {
				ra = re->createReactant();
				ra->setSpecies(edges.at(i)->endItem()->myId.toStdString());
				if (edges.at(i)->isComplex )
				{
					ra = re->createProduct();
					ra->setSpecies(edges.at(i)->complex->myId.toStdString());
				}
			 } else {
				ra = re->createProduct();
				ra->setSpecies(edges.at(i)->endItem()->myId.toStdString());
			}
			 for (int j = 0; j < edges.at(i)->conEdges.size() ; j++ )
			 {
				 if ( edges.at(i)->conEdges.at(j)->startItem()->diagramType() != 8 )
				 {
					ModifierSpeciesReference* mo = re->createModifier();
					mo->setSpecies(edges.at(i)->conEdges.at(j)->startItem()->myId.toStdString());
				 }
				 else
				{
					// contingency'nin contingency si
					/*
					string contingencyType = edges.at(i)->returnEnumSecond(edges.at(i)->edgeType()).toStdString(); // type
					string contingencyName = edges.at(i)->name; // name
					string contingencyId = edges.at(i)->myId.toStdString(); // id
					string controllerId = edges.at(i)->startItem()->host->myId.toStdString(); // controller id
					if ( edges.at(i)->startItem()->host->edgeType() < 10)// controller type
						string controllerType = "reaction";
					else
						string controllerType = "contingency";
					string controlledId = edges.at(i)->endItem()->host->myId.toStdString(); // controlled id
					if ( edges.at(i)->endItem()->host->edgeType() < 10) // controlled type
						string controllerType = "reaction";
					else
						string controllerType = "contingency";
					string contingencyAnnotation = edges.at(i)->annotation.toStdString();  */
				 }
			 }
		}

    }

    return sbmlDoc;   
}
bool Scene::validateSBML (SBMLDocument* sbmlDoc)
{
  if (!sbmlDoc)
  {
	QMessageBox msgBox;
	msgBox.setText("validateExampleSBML: given a null SBML Document" );
	msgBox.exec();
    return false;
  }

  string consistencyMessages;
  string validationMessages;
  bool noProblems                     = true;
  unsigned int numCheckFailures       = 0;
  unsigned int numConsistencyErrors   = 0;
  unsigned int numConsistencyWarnings = 0;
  unsigned int numValidationErrors    = 0;
  unsigned int numValidationWarnings  = 0;

  // LibSBML is lenient when generating models from scratch using the
  // API for creating objects.  Once the whole model is done and before it
  // gets written out, it's important to check that the whole model is in
  // fact complete, consistent and valid.

  numCheckFailures = sbmlDoc->checkInternalConsistency();
  if ( numCheckFailures > 0 )
  {
    noProblems = false;
    for (unsigned int i = 0; i < numCheckFailures; i++)
    {
      const SBMLError* sbmlErr = sbmlDoc->getError(i);
      if ( sbmlErr->isFatal() || sbmlErr->isError() )
      {
        ++numConsistencyErrors;
      }
      else
      {
        ++numConsistencyWarnings;
      }
    }
    ostringstream oss;
    sbmlDoc->printErrors(oss);
    consistencyMessages = oss.str();
  }

  // If the internal checks fail, it makes little sense to attempt
  // further validation, because the model may be too compromised to
  // be properly interpreted.

  if (numConsistencyErrors > 0)
  {
    consistencyMessages += "Further validation aborted.";
  }
  else
  {
    numCheckFailures = sbmlDoc->checkConsistency();
    if ( numCheckFailures > 0 )
    {
      noProblems = false;
      for (unsigned int i = 0; i < numCheckFailures; i++)
      {
        const SBMLError* sbmlErr = sbmlDoc->getError(i);
        if ( sbmlErr->isFatal() || sbmlErr->isError() )
        {
          ++numValidationErrors;
        }
        else
        {
          ++numValidationWarnings;
        }
      }
      ostringstream oss;
      sbmlDoc->printErrors(oss);
      validationMessages = oss.str();
    }
  }

  if (noProblems)
    return true;
  else
  {
    if (numConsistencyErrors > 0)
    {
		QMessageBox msgBox;
		msgBox.setText("ERROR: encountered " + QString::number(numConsistencyErrors)
           + " consistency error" + (numConsistencyErrors == 1 ? "" : "s")
           + " in model. " );
		msgBox.exec();
    }
    if (numConsistencyWarnings > 0)
    {
		/*QMessageBox msgBox;
		msgBox.setText("Notice: encountered " + QString::number(numConsistencyWarnings)
           + " consistency warning" + (numConsistencyWarnings == 1 ? "" : "s")
           + " in model. " );
		msgBox.exec(); */
    }
    cout << endl << consistencyMessages;

    if (numValidationErrors > 0)
    {
		QMessageBox msgBox;
		msgBox.setText("ERROR: encountered " + QString::number(numValidationErrors)
           + " validation error" + (numValidationErrors == 1 ? "" : "s")
           + " in model. " );
		msgBox.exec();
    }
    if (numValidationWarnings > 0)
    {
		/*QMessageBox msgBox;
		msgBox.setText("Notice: encountered " + QString::number(numValidationWarnings)
           + " validation warning" + (numValidationWarnings == 1 ? "" : "s")
           + " in model. " );
		msgBox.exec();*/
    }
    cout << endl << validationMessages;

    return (numConsistencyErrors == 0 && numValidationErrors == 0);
  }
}
bool Scene::writeExampleSBML(const SBMLDocument* sbmlDoc, const QString& filename)
{
  SBMLWriter sbmlWriter;

  bool result = sbmlWriter.writeSBML(sbmlDoc, filename.toStdString());

  if (result)
  {
    //cout << "Wrote file \"" << filename << "\"" << endl;
    return true;
  }
  else
  {
    //cerr << "Failed to write \"" << filename << "\"" << endl;
    return false;
  }
}
char* Scene::writeExampleSBML2(const SBMLDocument* sbmlDoc)
{
	SBMLWriter sbmlWriter;
	char* result;
	result = sbmlWriter.writeToString(sbmlDoc);
	return result;
}


void Scene::saveToSBML(const QString &fileName)
{
	  
	try
	{
		sbmlDoc = createExampleEnzymaticReaction(fileName);
		bool SBMLok  = validateSBML(sbmlDoc);
		if (SBMLok) writeExampleSBML(sbmlDoc,fileName);		
	}
	catch (std::bad_alloc& e)
	{
		cerr << e.what() << ": Unable to allocate memory." << endl;
		QMessageBox msgBox;
		msgBox.setText( e.what());
		msgBox.exec();
	}
	catch (...)
	{
		cerr << "Unexpected exceptional condition encountered." << endl;
		 QMessageBox msgBox;
		msgBox.setText("Unexpected exceptional condition encountered.");
		msgBox.exec();
		//return 1;
	}

  // A 0 return status is the standard Unix/Linux way to say "all ok".
}

char* Scene::saveToSBML2()
{	
	char* result;
	try
	{
		sbmlDoc = createExampleEnzymaticReaction("Model");
		bool SBMLok  = validateSBML(sbmlDoc);
		if (SBMLok) 
		{
			result = writeExampleSBML2(sbmlDoc);	
		}
	}
	catch (std::bad_alloc& e)
	{
		cerr << e.what() << ": Unable to allocate memory." << endl;
		QMessageBox msgBox;
		msgBox.setText( e.what());
		msgBox.exec();
	}
	catch (...)
	{
		cerr << "Unexpected exceptional condition encountered." << endl;
		 QMessageBox msgBox;
		msgBox.setText("Unexpected exceptional condition encountered.");
		msgBox.exec();
		//return 1;
	}
	return result;
}

int Scene::cross(const QPointF &p,const QPointF &p2)
{
	QPainterPath pa(p);
	pa.lineTo(p2);
	paItem = addPath(pa);
	foreach ( QGraphicsItem *item, paItem->collidingItems() )
	{
		if ( (item != selectedItems().first()) && (item != selectedItems().at(1)) )
		{
			removeItem(paItem);
			if (item->type() == DiagramItem::Type )
				return 2000;
			else
				return 20;
		}
	}
	removeItem(paItem);
	return 0;
}

void Scene::insertHeap(const QPointF &p)
{
	int i;
	heap.push_back(p);
	if ( heap.size() > 1 )
	{
		for ( i =  heap.size(); i > 1 && costArray[QString::number(int(heap.at(i/2-1).x())) + QString::number(int(heap.at(i/2-1).y()))] > costArray[QString::number(int(p.x())) + QString::number(int(p.y()))] ; i = i/2 )
			heap.replace(i-1,heap.at(i/2-1));
		heap.replace(i-1,p);
	}
}
void Scene::insertHeap2(const QPointF &p)
{
	int i;
	heap2.push_back(p);
	if ( heap2.size() > 1 )
	{
		for ( i =  heap2.size(); i > 1 && costArray2[QString::number(int(heap2.at(i/2-1).x())) + QString::number(int(heap2.at(i/2-1).y()))] > costArray2[QString::number(int(p.x())) + QString::number(int(p.y()))] ; i = i/2 )
			heap2.replace(i-1,heap2.at(i/2-1));
		heap2.replace(i-1,p);
	}
}
void Scene::decreaseKeyHeap(const QPointF &p)
{
	int i = 0,j;
	while ( heap.at(i) != p )
		i++;
	for ( j =  i+1 ; j > 2 && costArray[QString::number(int(heap.at(j/2-1).x())) + QString::number(int(heap.at(j/2-1).y()))] > costArray[QString::number(int(p.x())) + QString::number(int(p.y()))] ; j = j/2 )
		heap.replace(j-1,heap.at(j/2-1) );
	heap.replace(j-1,p);
}
void Scene::decreaseKeyHeap2(const QPointF &p)
{
	int i = 0,j;
	while ( heap2.at(i) != p )
		i++;
	for ( j =  i+1 ; j > 2 && costArray2[QString::number(int(heap2.at(j/2-1).x())) + QString::number(int(heap2.at(j/2-1).y()))] > costArray2[QString::number(int(p.x())) + QString::number(int(p.y()))] ; j = j/2 )
		heap2.replace(j-1,heap2.at(j/2-1) );
	heap2.replace(j-1,p);
}
void Scene::deleteMinHeap()
{

	int child,i;
	QPointF lastElement = heap.last();
	for(i = 0; (i+1)*2 <= heap.size() ; i = child )
	{
		child = (i+1)*2-1;
		if ( child != heap.size()-1 && costArray[QString::number(int(heap.at(child +1).x())) + QString::number(int(heap.at(child +1).y()))] < costArray[QString::number(int(heap.at(child).x()))+ QString::number(int(heap.at(child).y()))] )
			child++;
		if ( costArray[QString::number(int(heap.last().x())) + QString::number(int(heap.last().y()))] > costArray[QString::number(int(heap.at(child).x())) + QString::number(int(heap.at(child).y()))] )
			heap.replace(i,heap.at(child));
		else
			break;
	}

        heap.pop_back();
        if (!heap.isEmpty())
            heap.replace(i,lastElement);
}
void Scene::deleteMinHeap2()
{

	int child,i;
	QPointF lastElement = heap2.last();
	for(i = 0; (i+1)*2 <= heap2.size() ; i = child )
	{
		child = (i+1)*2-1;
		if ( child != heap2.size()-1 && costArray2[QString::number(int(heap2.at(child +1).x())) + QString::number(int(heap2.at(child +1).y()))] < costArray2[QString::number(int(heap2.at(child).x()))+ QString::number(int(heap2.at(child).y()))] )
			child++;
		if ( costArray2[QString::number(int(heap2.last().x())) + QString::number(int(heap2.last().y()))] > costArray2[QString::number(int(heap2.at(child).x())) + QString::number(int(heap2.at(child).y()))] )
			heap2.replace(i,heap2.at(child));
		else
			break;
	}

        heap2.pop_back();
        if (!heap2.isEmpty())
            heap2.replace(i,lastElement);
}
bool Scene::generateToAutoLayout()
{
	QString filename = "layoutText.txt";
	 QFile file(filename);
     if (!file.open(QFile::WriteOnly | QFile::Text)) {
         QMessageBox msgBox;
         msgBox.setText("Cannot write file.");
         msgBox.exec();
		 return false;
     }

     QTextStream out(&file);

	 out << QString::number(diagramItems.size()) << endl;

	 foreach (DiagramItem* item, diagramItems)
		 out << item->myId <<" " << QString::number(item->width) <<" " << QString::number(item->height) << endl;

	 out << QString::number(edges.size()) << endl;
	
	 foreach (Edge* edge, edges)
		 out << edge->startItem()->myId << " " << edge->endItem()->myId << endl;

	 return true;
}
void Scene::addBranch(bool right)
{
	QList<QGraphicsItem *> Item = selectedItems();
	if ( Item.first()->type() == Edge::Type )
	{
		Edge *item = qgraphicsitem_cast<Edge *>(Item.first());
		if ( right)
		{
			item->branchRight = true;
			item->branchLeft = false;
		}
		else
		{
			item->branchLeft = true;
			item->branchRight = false;
		}
	}

}


		



